﻿#region 信息

// Copyright©2014 Rex Rao all rights reserved.
// File name : SoMcCoffee\Sohobloo.SoMcCoffee\UnitOfWorkContextBase.cs
// Author : Sohobloo
// Create time : 2014/01/31 23:40
// Update time : 2014/02/05 8:57

#endregion

#region 引用

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Data.Entity;
using System.Data.Entity.Validation;
using Sohobloo.SoCommon;
using Sohobloo.SoCommon.CommonExtension;
using Sohobloo.SoCommon.Log;
using Sohobloo.SoMcCoffee.Entity;

#endregion

namespace Sohobloo.SoMcCoffee.Data
{
    /// <summary>
    ///     单元操作实现
    /// </summary>
    internal abstract class UnitOfWorkContextBase : IUnitOfWorkContext
    {
        #region 属性

        /// <summary>
        ///     获取 当前使用的数据访问上下文对象
        /// </summary>
        protected abstract DbContext Context { get; }

        /// <summary>
        ///     操作员
        /// </summary>
        [Import]
        protected IOperator DbOperator { get; set; }

        /// <summary>
        ///     获取 当前单元操作是否已被提交
        /// </summary>
        public bool IsCommitted { get; private set; }

        #endregion 属性

        #region 方法

        /// <summary>
        ///     提交当前单元操作的结果
        /// </summary>
        /// <returns></returns>
        public int Commit()
        {
            int result;
            if(IsCommitted)
            {
                return 0;
            }
            try
            {
                result = Context.SaveChanges();
            }
            catch(DbEntityValidationException dbEx)
            {
                Logger.LogError("DbEntityValidationException", dbEx, DbOperator);
                throw;
            }

            IsCommitted = true;
            return result;
        }

        /// <summary>
        ///     把当前单元操作回滚成未提交状态
        /// </summary>
        public void Rollback()
        {
            IsCommitted = false;
        }

        public void Dispose()
        {
            if(!IsCommitted)
            {
                Commit();
            }
            Context.Dispose();
        }

        /// <summary>
        ///     为指定的类型返回 System.Data.Entity.DbSet，这将允许对上下文中的给定实体执行 CRUD 操作。
        /// </summary>
        /// <typeparam name="TEntity"> 应为其返回一个集的实体类型。 </typeparam>
        /// <returns> 给定实体类型的 System.Data.Entity.DbSet 实例。 </returns>
        public DbSet<TEntity> Set<TEntity>() where TEntity : EntityBase
        {
            return Context.Set<TEntity>();
        }

        /// <summary>
        ///     注册一个新的对象到仓储上下文中
        /// </summary>
        /// <typeparam name="TEntity"> 要注册的类型 </typeparam>
        /// <param name="entity"> 要注册的对象 </param>
        public void RegisterNew<TEntity>(TEntity entity) where TEntity : EntityBase
        {
            var state = Context.Entry(entity).State;
            if(state == EntityState.Detached)
            {
                Context.Entry(entity).State = EntityState.Added;
            }
            entity.CreateTime = entity.UpdateTime = DateTime.UtcNow;
            if(DbOperator.IsNotNull())
            {
                entity.CreateUser = entity.UpdateUser = DbOperator.Name;
            }
            if(entity.EnableSort)
            {
                entity.SortIndex = entity.CreateTime.Ticks;
            }
            IsCommitted = false;
        }

        /// <summary>
        ///     批量注册多个新的对象到仓储上下文中
        /// </summary>
        /// <typeparam name="TEntity"> 要注册的类型 </typeparam>
        /// <param name="entities"> 要注册的对象集合 </param>
        public void RegisterNew<TEntity>(IEnumerable<TEntity> entities) where TEntity : EntityBase
        {
            try
            {
                Context.Configuration.AutoDetectChangesEnabled = false;
                foreach(var entity in entities)
                {
                    RegisterNew(entity);
                }
            }
            finally
            {
                Context.Configuration.AutoDetectChangesEnabled = true;
            }
        }

        /// <summary>
        ///     注册一个更改的对象到仓储上下文中
        /// </summary>
        /// <typeparam name="TEntity"> 要注册的类型 </typeparam>
        /// <param name="entity"> 要注册的对象 </param>
        /// <param name="logModification"></param>
        public void RegisterModified<TEntity>(TEntity entity, bool logModification) where TEntity : EntityBase
        {
            if(Context.Entry(entity).State == EntityState.Detached)
            {
                Context.Set<TEntity>().Attach(entity);
            }
            if(logModification)
            {
                entity.UpdateTime = DateTime.UtcNow;
                if (DbOperator.IsNotNull())
                {
                    entity.UpdateUser = DbOperator.Name;
                }
            }
            Context.Entry(entity).State = EntityState.Modified;
            IsCommitted = false;
        }

        /// <summary>
        ///     批量注册多个修改的对象到仓储上下文中
        /// </summary>
        /// <typeparam name="TEntity"> 要注册的类型 </typeparam>
        /// <param name="entities"> 要注册的对象集合 </param>
        /// <param name="logModification">是否记录变更</param>
        public void RegisterModified<TEntity>(IEnumerable<TEntity> entities, bool logModification) where TEntity : EntityBase
        {
            try
            {
                Context.Configuration.AutoDetectChangesEnabled = false;
                foreach (var entity in entities)
                {
                    RegisterModified(entity, logModification);
                }
            }
            finally
            {
                Context.Configuration.AutoDetectChangesEnabled = true;
            }
        }

        /// <summary>
        ///     注册一个删除的对象到仓储上下文中
        /// </summary>
        /// <typeparam name="TEntity"> 要注册的类型 </typeparam>
        /// <param name="entity"> 要注册的对象 </param>
        public void RegisterDeleted<TEntity>(TEntity entity) where TEntity : EntityBase
        {
            Context.Entry(entity).State = EntityState.Deleted;
            IsCommitted = false;
        }

        /// <summary>
        ///     批量注册多个删除的对象到仓储上下文中
        /// </summary>
        /// <typeparam name="TEntity"> 要注册的类型 </typeparam>
        /// <param name="entities"> 要注册的对象集合 </param>
        public void RegisterDeleted<TEntity>(IEnumerable<TEntity> entities) where TEntity : EntityBase
        {
            try
            {
                Context.Configuration.AutoDetectChangesEnabled = false;
                foreach(var entity in entities)
                {
                    RegisterDeleted(entity);
                }
            }
            finally
            {
                Context.Configuration.AutoDetectChangesEnabled = true;
            }
        }

        #endregion 方法
    }
}